package com.school.sports.service.Impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.school.sports.entity.OperationLog;
import com.school.sports.mapper.OperationLogMapper;
import com.school.sports.service.OperationLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 操作日志服务实现类
 */
@Service
public class OperationLogServiceImpl extends ServiceImpl<OperationLogMapper, OperationLog> implements OperationLogService {

    private static final Logger logger = LoggerFactory.getLogger(OperationLogServiceImpl.class);

    @Override
    public IPage<OperationLog> getOperationLogPage(Integer currentPage, Integer pageSize, OperationLog operationLog) {
        logger.info("分页查询操作日志，当前页码：{}，每页条数：{}，查询条件：{}", currentPage, pageSize, operationLog);

        // 创建分页对象
        Page<OperationLog> page = new Page<>(currentPage, pageSize);

        // 构建查询条件
        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();

        // 按用户名查询
        if (StringUtils.hasText(operationLog.getUsername())) {
            queryWrapper.like("username", operationLog.getUsername());
        }

        // 按操作类型查询
        if (StringUtils.hasText(operationLog.getOperationType())) {
            queryWrapper.eq("operation_type", operationLog.getOperationType());
        }

        // 按模块查询
        if (StringUtils.hasText(operationLog.getModule())) {
            queryWrapper.like("module", operationLog.getModule());
        }

        // 按状态查询
        if (operationLog.getStatus() != null) {
            queryWrapper.eq("status", operationLog.getStatus());
        }

        // 按IP地址查询
        if (StringUtils.hasText(operationLog.getIpAddress())) {
            queryWrapper.like("ip_address", operationLog.getIpAddress());
        }

        // 按时间范围查询
        if (operationLog.getOperationTime() != null) {
            queryWrapper.ge("operation_time", operationLog.getOperationTime());
        }

        // 按时间范围查询（如果有结束时间）
        // 这里可以在实体类中添加一个endTime字段，或者通过参数传递

        // 排序：按操作时间倒序
        queryWrapper.orderByDesc("operation_time");

        // 执行分页查询
        IPage<OperationLog> result = this.page(page, queryWrapper);

        logger.info("查询操作日志成功，共{}条记录", result.getTotal());
        return result;
    }

    @Override
    public boolean saveOperationLog(OperationLog operationLog) {
        logger.info("保存操作日志：用户ID={}，操作类型={}，描述={}",
                   operationLog.getUserId(), operationLog.getOperationType(), operationLog.getDescription());

        try {
            // 设置创建时间和更新时间
            LocalDateTime now = LocalDateTime.now();
            operationLog.setCreatedAt(now);
            operationLog.setUpdatedAt(now);

            // 如果操作时间为空，设置为当前时间
            if (operationLog.getOperationTime() == null) {
                operationLog.setOperationTime(now);
            }

            // 保存操作日志
            boolean result = this.save(operationLog);

            if (result) {
                logger.info("保存操作日志成功，ID：{}", operationLog.getId());
            } else {
                logger.error("保存操作日志失败");
            }

            return result;
        } catch (Exception e) {
            logger.error("保存操作日志异常：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public List<OperationLog> getOperationLogsByUserId(Long userId, Integer limit) {
        logger.info("根据用户ID查询操作日志，用户ID：{}，限制条数：{}", userId, limit);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.orderByDesc("operation_time");

        // 设置查询限制
        if (limit != null && limit > 0) {
            queryWrapper.last("LIMIT " + limit);
        }

        List<OperationLog> result = this.list(queryWrapper);
        logger.info("查询成功，共{}条记录", result.size());
        return result;
    }

    @Override
    public List<OperationLog> getOperationLogsByType(String operationType, Integer limit) {
        logger.info("根据操作类型查询操作日志，操作类型：{}，限制条数：{}", operationType, limit);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("operation_type", operationType);
        queryWrapper.orderByDesc("operation_time");

        // 设置查询限制
        if (limit != null && limit > 0) {
            queryWrapper.last("LIMIT " + limit);
        }

        List<OperationLog> result = this.list(queryWrapper);
        logger.info("查询成功，共{}条记录", result.size());
        return result;
    }

    @Override
    public List<OperationLog> getOperationLogsByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
        logger.info("根据时间范围查询操作日志，开始时间：{}，结束时间：{}", startTime, endTime);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();

        if (startTime != null) {
            queryWrapper.ge("operation_time", startTime);
        }

        if (endTime != null) {
            queryWrapper.le("operation_time", endTime);
        }

        queryWrapper.orderByDesc("operation_time");

        List<OperationLog> result = this.list(queryWrapper);
        logger.info("查询成功，共{}条记录", result.size());
        return result;
    }

    @Override
    public Map<String, Long> countByOperationType(LocalDateTime startTime, LocalDateTime endTime) {
        logger.info("统计各类型操作日志数量，开始时间：{}，结束时间：{}", startTime, endTime);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("operation_type", "COUNT(*) as count");

        if (startTime != null) {
            queryWrapper.ge("operation_time", startTime);
        }

        if (endTime != null) {
            queryWrapper.le("operation_time", endTime);
        }

        queryWrapper.groupBy("operation_type");

        List<Map<String, Object>> resultList = this.listMaps(queryWrapper);

        Map<String, Long> result = new HashMap<>();
        for (Map<String, Object> map : resultList) {
            String type = (String) map.get("operation_type");
            Long count = ((Number) map.get("count")).longValue();
            result.put(type, count);
        }

        logger.info("统计完成，共{}种操作类型", result.size());
        return result;
    }

    @Override
    public List<Map<String, Object>> countByUserId(LocalDateTime startTime, LocalDateTime endTime, Integer topN) {
        logger.info("统计用户操作次数，开始时间：{}，结束时间：{}，前N名：{}", startTime, endTime, topN);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_id", "username", "COUNT(*) as count");

        if (startTime != null) {
            queryWrapper.ge("operation_time", startTime);
        }

        if (endTime != null) {
            queryWrapper.le("operation_time", endTime);
        }

        queryWrapper.groupBy("user_id", "username");
        queryWrapper.orderByDesc("count");

        if (topN != null && topN > 0) {
            queryWrapper.last("LIMIT " + topN);
        }

        List<Map<String, Object>> result = this.listMaps(queryWrapper);
        logger.info("统计完成，共{}个用户", result.size());
        return result;
    }

    @Override
    public List<Map<String, Object>> countByDate(LocalDateTime startTime, LocalDateTime endTime) {
        logger.info("统计每日操作数量，开始时间：{}，结束时间：{}", startTime, endTime);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DATE(operation_time) as date", "COUNT(*) as count");

        if (startTime != null) {
            queryWrapper.ge("operation_time", startTime);
        }

        if (endTime != null) {
            queryWrapper.le("operation_time", endTime);
        }

        queryWrapper.groupBy("DATE(operation_time)");
        queryWrapper.orderByAsc("date");

        List<Map<String, Object>> result = this.listMaps(queryWrapper);
        logger.info("统计完成，共{}天", result.size());
        return result;
    }

    @Override
    public Long countFailedOperations(LocalDateTime startTime, LocalDateTime endTime) {
        logger.info("统计失败操作数量，开始时间：{}，结束时间：{}", startTime, endTime);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 0); // 失败状态

        if (startTime != null) {
            queryWrapper.ge("operation_time", startTime);
        }

        if (endTime != null) {
            queryWrapper.le("operation_time", endTime);
        }

        Long count = this.count(queryWrapper);
        logger.info("统计完成，失败操作数量：{}", count);
        return count;
    }

    @Override
    public void exportOperationLogs(OperationLog operationLog, HttpServletResponse response) {
        logger.info("导出操作日志，查询条件：{}", operationLog);

        try {
            // 设置响应头
            String fileName = "操作日志_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".xlsx";
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

            // 查询数据
            QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();

            // 构建查询条件（与分页查询相同的逻辑）
            if (StringUtils.hasText(operationLog.getUsername())) {
                queryWrapper.like("username", operationLog.getUsername());
            }
            if (StringUtils.hasText(operationLog.getOperationType())) {
                queryWrapper.eq("operation_type", operationLog.getOperationType());
            }
            if (StringUtils.hasText(operationLog.getModule())) {
                queryWrapper.like("module", operationLog.getModule());
            }
            if (operationLog.getStatus() != null) {
                queryWrapper.eq("status", operationLog.getStatus());
            }
            if (StringUtils.hasText(operationLog.getIpAddress())) {
                queryWrapper.like("ip_address", operationLog.getIpAddress());
            }

            queryWrapper.orderByDesc("operation_time");

            List<OperationLog> operationLogs = this.list(queryWrapper);

            // 写入Excel
            EasyExcel.write(response.getOutputStream(), OperationLog.class)
                    .sheet("操作日志")
                    .doWrite(operationLogs);

            logger.info("导出操作日志成功，共{}条记录", operationLogs.size());

        } catch (IOException e) {
            logger.error("导出操作日志异常：{}", e.getMessage(), e);
            throw new RuntimeException("导出失败：" + e.getMessage());
        }
    }

    @Override
    public boolean batchDeleteLogs(List<Long> ids) {
        logger.info("批量删除操作日志，ID列表：{}", ids);

        if (ids == null || ids.isEmpty()) {
            return false;
        }

        try {
            boolean result = this.removeByIds(ids);
            if (result) {
                logger.info("批量删除操作日志成功，共{}条记录", ids.size());
            } else {
                logger.error("批量删除操作日志失败");
            }
            return result;
        } catch (Exception e) {
            logger.error("批量删除操作日志异常：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public Integer cleanLogsBeforeTime(LocalDateTime beforeTime) {
        logger.info("清理指定时间之前的日志，时间点：{}", beforeTime);

        if (beforeTime == null) {
            return 0;
        }

        try {
            QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
            queryWrapper.lt("operation_time", beforeTime);

            long totalCount = this.count(queryWrapper);
            int count = (int) totalCount;

            if (count > 0) {
                this.remove(queryWrapper);
                logger.info("清理操作日志成功，共{}条记录", count);
            }

            return count;
        } catch (Exception e) {
            logger.error("清理操作日志异常：{}", e.getMessage(), e);
            return 0;
        }
    }

    @Override
    public List<OperationLog> getRecentOperationLogs(Integer limit) {
        logger.info("获取最近的操作日志，限制条数：{}", limit);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("operation_time");

        if (limit != null && limit > 0) {
            queryWrapper.last("LIMIT " + limit);
        }

        List<OperationLog> result = this.list(queryWrapper);
        logger.info("查询成功，共{}条记录", result.size());
        return result;
    }

    @Override
    public List<OperationLog> getOperationLogsByIp(String ipAddress, Integer limit) {
        logger.info("根据IP地址查询操作日志，IP地址：{}，限制条数：{}", ipAddress, limit);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ip_address", ipAddress);
        queryWrapper.orderByDesc("operation_time");

        if (limit != null && limit > 0) {
            queryWrapper.last("LIMIT " + limit);
        }

        List<OperationLog> result = this.list(queryWrapper);
        logger.info("查询成功，共{}条记录", result.size());
        return result;
    }

    @Override
    public List<Map<String, Object>> checkAbnormalOperations(Integer timeWindow, Integer threshold) {
        logger.info("检查异常操作，时间窗口：{}分钟，阈值：{}", timeWindow, threshold);

        // 这里可以实现更复杂的异常检测逻辑
        // 比如：检查同一用户在短时间内的操作次数、检查异常IP等

        List<Map<String, Object>> abnormalOperations = new ArrayList<>();

        // 示例：检查频繁操作的用户
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime startTime = endTime.minusMinutes(timeWindow);

        QueryWrapper<OperationLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_id", "username", "ip_address", "COUNT(*) as count");
        queryWrapper.ge("operation_time", startTime);
        queryWrapper.le("operation_time", endTime);
        queryWrapper.groupBy("user_id", "username", "ip_address");
        queryWrapper.having("COUNT(*) > {0}", threshold);

        List<Map<String, Object>> frequentOperations = this.listMaps(queryWrapper);

        for (Map<String, Object> operation : frequentOperations) {
            Map<String, Object> abnormal = new HashMap<>();
            abnormal.put("type", "频繁操作");
            abnormal.put("userId", operation.get("user_id"));
            abnormal.put("username", operation.get("username"));
            abnormal.put("ipAddress", operation.get("ip_address"));
            abnormal.put("count", operation.get("count"));
            abnormal.put("timeWindow", timeWindow + "分钟");
            abnormalOperations.add(abnormal);
        }

        logger.info("异常操作检查完成，发现{}个异常", abnormalOperations.size());
        return abnormalOperations;
    }
}